local skynet = require "skynet"
local proto_manager = require "common.proto_manager"
local match_room = require "match.match_room"
local service_helper = require "common.service_helper"
local MessageType = require "common.message_type"

local match_manager = {}

local matchIdCount = 0

local matchingPool = {}

local matchedPool = {}

local players = {}

local function onNotifyMatchInfo(matchInfo,open_id,infos)

    local data = {
        open_ids = {open_id},
        message_id = "MessageId_NotifyMatchInfo",
        message_type = "MessageNotifyMatchInfo",
        msg = {
            match_id = matchInfo:getID(),
            players = infos,
        },
    }

    service_helper.send2Agent(MessageType.Forward2Client,data)

end

local function onNotifyGameStart(matchInfo)

    matchInfo:foreachPlayers(function(player)
        local data = {
            open_ids = {player.open_id},
            message_id = "MessageId_NotifyGameStart",
            message_type = "MessageNotifyGameStart",
            msg = matchInfo:getGameStartInfo(player.open_id),
        }

        service_helper.send2Agent(MessageType.Forward2Client,data)
    end)

end

local function onNotifyGameEnd(matchInfo,info)

    match_manager.end_match(matchInfo:getID())

    service_helper.send2Race(MessageType.DestroyRaceRoom,{room_id=matchInfo:getID()})

    matchInfo:foreachPlayers(function(player)

        local data = {
            open_id = player.open_id,
            result = proto_manager.ErrorCode_Successed,
            room_id = matchInfo:getID(),
            players = info.players,
        }
        service_helper.send2Agent(MessageType.MessageId_EndGameResp,data)

    end)

end

local function onNotifyGameEndFailed(matchInfo,result)

    match_manager.end_match(matchInfo:getID())

    service_helper.send2Race(MessageType.DestroyRaceRoom,{room_id=matchInfo:getID()})

    matchInfo:foreachPlayers(function(player)

        local data = {
            open_id = player.open_id,
            result = result,
            room_id = matchInfo:getID(),
        }
        service_helper.send2Agent(MessageType.MessageId_NotifyGameEndFailed,data)

    end)

end


function match_manager.getMatchByOpenID(openid)
    return players[openid] or nil
end

function match_manager.getMatchingByID(id)
    return matchingPool[id] or nil
end

function match_manager.getMatchedByID(id)
    return matchedPool[id] or nil
end

function match_manager.online(playerInfo)

    local matchInfo = players[playerInfo.open_id]
    if not matchInfo then
        return false
    end

    matchInfo:setOnline(playerInfo.open_id)

    return true

end

function match_manager.offline(open_id)

    local matchInfo = players[open_id]
    if not matchInfo then
        return false
    end

    if matchInfo:canLeave() then
        matchInfo:removePlayer(open_id)
    else
        matchInfo:setOffline(open_id)
    end

    return true

end

function match_manager.enter_match(playerInfo)

    if players[playerInfo.open_id] then
        return false
    end

    local matchInfo

    if next(matchingPool) then

        for k,v in pairs(matchingPool) do
            matchInfo = v
            matchingPool[k] = nil
            break
        end

        matchInfo:addPlayer(playerInfo)

        players[playerInfo.open_id] = matchInfo

        matchedPool[matchInfo:getID()] = matchInfo

        return true,matchInfo

    else

        matchIdCount = matchIdCount + 1

        matchInfo = match_room:new(matchIdCount)
        matchInfo.onNotifyMatchInfo = onNotifyMatchInfo
        matchInfo.onNotifyGameStart = onNotifyGameStart
        matchInfo.onNotifyGameEnd = onNotifyGameEnd
        matchInfo.onNotifyGameEndFailed = onNotifyGameEndFailed

        matchInfo:addPlayer(playerInfo)

        matchingPool[matchInfo:getID()] = matchInfo

        players[playerInfo.open_id] = matchInfo

        return true,matchInfo

    end

end

function match_manager.end_match(match_id)

    local matchInfo = matchingPool[match_id] or matchedPool[match_id] or nil

    if matchInfo then
        matchInfo:foreachPlayers(function(playerInfo)
            players[playerInfo.open_id] = nil
        end)
    end

    matchingPool[match_id] = nil
    matchedPool[match_id] = nil

    return matchInfo ~= nil

end

function match_manager.onMatchRaceException(match_id,result)

    local matchInfo = matchingPool[match_id] or matchedPool[match_id] or nil

    if matchInfo then
        onNotifyGameEndFailed(matchInfo,result)
    end

end

function match_manager.player_leave(openid)

    local matchInfo = players[openid]

    if not matchInfo then
        return false
    end

    players[openid] = nil

    if matchingPool[matchInfo:getID()] then

        matchInfo:removePlayer(openid)

        assert(matchInfo:isEmpty())

        matchingPool[matchInfo:getID()] = nil

    elseif matchedPool[matchInfo:getID()] then

        matchInfo:removePlayer(openid)

        assert(not matchInfo:isEmpty())

        matchedPool[matchInfo:getID()] = nil

        matchingPool[matchInfo:getID()] = matchInfo

    else
        skynet.error("match_manager|player_leave not find pool match_id:"
                .. tostring(matchInfo:getID()) .. " openid:" .. openid)
        return false
    end

    return true,matchInfo

end

return match_manager